package io.youngledo.usb.license;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Scanner;

/// 许可证生成器（开发者工具）
///
/// ⚠️ **此工具仅供开发者使用**，用于生成付费许可证。
/// 需要提供私钥文件才能运行。
///
/// ## 使用方法
/// ```bash
/// java io.youngledo.usb.license.LicenseGenerator
/// ```
///
/// ## 生成流程
/// 1. 加载私钥文件 (private_key.pem)
/// 2. 输入用户信息（邮箱、姓名）
/// 3. 选择许可证类型（专业版/企业版）
/// 4. 设置有效期（永久/指定时间）
/// 5. 可选：绑定机器ID
/// 6. 生成签名并保存许可证文件
public class LicenseGenerator {

    private static final ObjectMapper objectMapper = createObjectMapper();

    private static ObjectMapper createObjectMapper() {
        var mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return mapper;
    }

    static void main() {
        var scanner = new Scanner(System.in);

        System.out.println("========================================");
        System.out.println("🔑 通用存储浏览器 - 许可证生成器");
        System.out.println("========================================\n");

        try {
            // 1. 加载私钥
            System.out.print("请输入私钥文件路径 [默认: ./private_key.pem]: ");
            var privateKeyPath = scanner.nextLine().trim();
            if (privateKeyPath.isEmpty()) {
                privateKeyPath = "./private_key.pem";
            }

            System.out.println("正在加载私钥: " + privateKeyPath);
            var privateKey = KeyManager.loadPrivateKey(Path.of(privateKeyPath));
            System.out.println("✅ 私钥加载成功\n");

            // 2. 输入用户信息
            System.out.print("用户邮箱: ");
            var userId = scanner.nextLine().trim();

            System.out.print("用户姓名: ");
            var userName = scanner.nextLine().trim();

            // 3. 选择许可证类型
            System.out.println("\n许可证类型：");
            System.out.println("1. 专业版 (PROFESSIONAL)");
            System.out.print("请选择 [1]: ");
            var typeChoice = scanner.nextLine().trim();

            var licenseType = LicenseType.PROFESSIONAL; // 只有专业版可选

            // 4. 设置有效期
            System.out.println("\n有效期设置：");
            System.out.println("1. 永久有效");
            System.out.println("2. 1年");
            System.out.println("3. 自定义月数");
            System.out.print("请选择 [1-3]: ");
            var expiryChoice = scanner.nextLine().trim();

            LocalDateTime expiryDate = switch (expiryChoice) {
                case "2" -> LocalDateTime.now().plusYears(1);
                case "3" -> {
                    System.out.print("请输入有效月数: ");
                    var months = Integer.parseInt(scanner.nextLine().trim());
                    yield LocalDateTime.now().plusMonths(months);
                }
                default -> null; // 永久有效
            };

            // 5. 机器ID绑定（可选）
            System.out.print("\n是否绑定机器ID？(y/N): ");
            var bindMachine = scanner.nextLine().trim().equalsIgnoreCase("y");

            String machineId = null;
            if (bindMachine) {
                System.out.println("当前机器ID: " + MachineIdGenerator.getMachineId());
                System.out.print("请输入要绑定的机器ID [默认：当前机器]: ");
                var inputMachineId = scanner.nextLine().trim();
                machineId = inputMachineId.isEmpty() ? MachineIdGenerator.getMachineId() : inputMachineId;
            }

            // 6. 启用的功能
            var enabledFeatures = List.of(
                    Feature.BATCH_OPERATIONS,
                    Feature.TASK_MANAGEMENT,
                    Feature.UNLIMITED_CONNECTIONS,
                    Feature.ADVANCED_UI,
                    Feature.ADVANCED_PROGRESS
            );

            // 7. 生成许可证密钥
            var licenseKey = generateLicenseKey();

            // 8. 创建许可证对象（不含签名）
            var licenseWithoutSignature = new License(
                    licenseKey,
                    licenseType,
                    userId,
                    userName,
                    LocalDateTime.now(),
                    expiryDate,
                    machineId,
                    enabledFeatures,
                    "" // 签名稍后生成
            );

            // 9. 生成签名
            System.out.println("\n正在生成签名...");
            var signature = LicenseValidator.sign(licenseWithoutSignature, privateKey);

            // 10. 创建完整的许可证
            var license = new License(
                    licenseKey,
                    licenseType,
                    userId,
                    userName,
                    LocalDateTime.now(),
                    expiryDate,
                    machineId,
                    enabledFeatures,
                    signature
            );

            // 11. 保存许可证文件
            var outputPath = Path.of(String.format("license_%s.json", userId.replace("@", "_")));
            var json = objectMapper.writeValueAsString(license);
            java.nio.file.Files.writeString(outputPath, json);

            // 12. 输出结果
            System.out.println("\n========================================");
            System.out.println("✅ 许可证生成成功！");
            System.out.println("========================================");
            System.out.println(license.getDisplayInfo());
            System.out.println("许可证密钥: " + licenseKey);
            System.out.println("保存路径: " + outputPath.toAbsolutePath());
            System.out.println("========================================\n");

            System.out.println("📋 许可证文件内容：\n");
            System.out.println(json);
            System.out.println("\n请将此文件发送给用户，或提供许可证密钥供用户激活。");

        } catch (Exception e) {
            System.err.println("\n❌ 许可证生成失败: " + e.getMessage());
            e.printStackTrace();
        } finally {
            scanner.close();
        }
    }

    /// 生成许可证密钥（格式：XXXX-XXXX-XXXX-XXXX）
    private static String generateLicenseKey() {
        var random = new java.security.SecureRandom();
        var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var key = new StringBuilder();

        for (int i = 0; i < 4; i++) {
            if (i > 0) key.append("-");
            for (int j = 0; j < 4; j++) {
                key.append(chars.charAt(random.nextInt(chars.length())));
            }
        }

        return key.toString();
    }
}
